//! Function declaration parser

use super::super::{parse_expression, parse_type, Parser};
use super::helpers::{parse_attributes, parse_block, parse_where_clause_for_generics};
use super::impl_decl::parse_method_declaration;
use crate::ast::decl::GenericParam;
use crate::error::{CompilerError, Result};
use crate::lexer::token::Token;

/// Parse function declaration
pub fn parse_function_declaration(parser: &mut Parser) -> Result<crate::ast::FunctionDecl> {
    parser.expect(&Token::Fn)?;

    // Check if this is a Go-style method (has receiver)
    if parser.check(&Token::LeftParen) {
        // This is a Go-style method, parse it as a method declaration
        if let Some(method) = parse_method_declaration(parser)? {
            return Ok(method);
        } else {
            return Err(CompilerError::syntax(
                parser.current_location().line,
                parser.current_location().column,
                "Failed to parse method declaration",
            ));
        }
    }

    if let Some(Token::Identifier(name)) = parser.peek().map(|t| &t.token) {
        let func_name = name.clone();
        parser.advance()?;

        // Parse generic type parameters
        let mut generics = if parser.consume(&Token::Less)? {
            let mut generics = Vec::new();

            if !parser.check(&Token::Greater) {
                loop {
                    if let Some(Token::Identifier(generic_name)) = parser.peek().map(|t| &t.token) {
                        let name = generic_name.clone();
                        parser.advance()?;

                        // Parse constraints
                        let constraints = if parser.consume(&Token::Colon)? {
                            let mut constraints = Vec::new();

                            loop {
                                if let Some(constraint) = parse_type(parser)? {
                                    constraints.push(constraint);
                                }

                                if !parser.consume(&Token::Plus)? {
                                    break;
                                }
                            }

                            constraints
                        } else {
                            vec![]
                        };

                        generics.push(GenericParam {
                            name,
                            constraints,
                            location: parser.current_location(),
                        });
                    }

                    if !parser.consume(&Token::Comma)? {
                        break;
                    }
                }
            }

            parser.expect(&Token::Greater)?;
            generics
        } else {
            vec![]
        };

        // Parse parameters
        parser.expect(&Token::LeftParen)?;
        let mut parameters = Vec::new();

        if !parser.check(&Token::RightParen) {
            loop {
                // Parse parameter name first (NRC syntax: name type)
                if let Some(Token::Identifier(param_name)) = parser.peek().map(|t| &t.token) {
                    let name = param_name.clone();
                    parser.advance()?;

                    // Parse parameter type
                    let param_type = parse_type(parser)?;
                    if param_type.is_none() {
                        return Err(CompilerError::syntax(
                            parser.current_location().line,
                            parser.current_location().column,
                            "Expected parameter type",
                        ));
                    }

                    // Parse default value
                    let default_value = if parser.consume(&Token::Assign)? {
                        parse_expression(parser)?
                    } else {
                        None
                    };

                    parameters.push(crate::ast::types::Parameter {
                        name,
                        param_type: param_type.unwrap(),
                        default_value,
                        location: parser.current_location(),
                    });
                } else {
                    return Err(CompilerError::syntax(
                        parser.current_location().line,
                        parser.current_location().column,
                        "Expected parameter name",
                    ));
                }

                if !parser.consume(&Token::Comma)? {
                    break;
                }
            }
        }

        parser.expect(&Token::RightParen)?;

        // Parse return type (Golang风格：直接在参数后，不需要冒号或箭头)
        // 只支持单返回值: func name() Type {}
        let return_type = if !parser.check(&Token::LeftBrace) {
            // Single return value only
            parse_type(parser)?
        } else {
            None
        };

        // Parse optional where-clause (syntax sugar for generic constraints)
        parse_where_clause_for_generics(parser, &mut generics)?;

        // Parse function body
        let body = if parser.consume(&Token::LeftBrace)? {
            Some(parse_block(parser)?)
        } else {
            None
        };

        // Parse attributes
        let attributes = parse_attributes(parser)?;

        Ok(crate::ast::FunctionDecl {
            name: func_name,
            generics,
            parameters,
            return_type,
            body,
            attributes,
            location: parser.current_location(),
        })
    } else {
        Err(CompilerError::syntax(
            parser.current_location().line,
            parser.current_location().column,
            "Expected function name after 'fn'",
        ))
    }
}
